package cn.com.basic.framework.datasource.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.SystemPropertyUtils;

import java.util.LinkedHashSet;
import java.util.Set;

// 工具类：获取指定包下的类
@Slf4j
public final class AnnotationMetaDataBeanUtil {
    //扫描  scanPackages 下的文件匹配符
    public static final String DEFAULT_RESOURCE_PATTERN = "/**/*.class";

    // 获取Spring资源解析器
    private static final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    // 创建Spring中用来读取resource为class的工具类
    private static final MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);

    /**
     * 找到 scanPackages 下带注解 annotation 的全部类信息
     *
     * @param scanPackages 扫描包集合
     * @return fullClassNameSet 获取指定包及其子包下带有此注解的全类名集合
     */
    public static Set<String> findPackageAnnotationClass(String... scanPackages) {
        Set<String> annotationMetadataSet = new LinkedHashSet<>();

        if (scanPackages == null || scanPackages.length == 0) {
            return annotationMetadataSet;
        }
        for (String basePackage : scanPackages) {
            if (StringUtils.isEmpty(basePackage)) {
                continue;
            }
            String packageSearchPath
                    = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(
                            SystemPropertyUtils.resolvePlaceholders(basePackage))
                    + DEFAULT_RESOURCE_PATTERN;

            // 获取packageSearchPath下的Resource，这里得到的Resource是Class信息
            try {
                Resource[] resources =
                        resourcePatternResolver.getResources(packageSearchPath);
                for (Resource resource : resources) {
                    MetadataReader metadataReader =
                            metadataReaderFactory.getMetadataReader(resource);
                    annotationMetadataSet.add(metadataReader.getAnnotationMetadata()
                            .getClassName());
                }
            } catch (Exception e) {
                log.error("获取包下面的类信息失败,package:" + basePackage, e);
            }
        }
        return annotationMetadataSet;
    }
}